package main

import (
    "context"
    "fmt"
    modbus "github.com/thinkgos/gomodbus/v2"
    "log"
    "math/rand"
    "sync"
    "time"
)

// ============ 配置 ============
type Device struct {
    ID   int
    IP   string
    Port int
}

var devices = []Device{
    {ID: 1, IP: "127.0.0.1", Port: 502},
}

const (
    pollInterval  = 1 * time.Second
    tcpTimeout    = 1 * time.Second
    failThreshold = 3 // 连续失败 3 次 → 离线
    okThreshold   = 2 // 连续成功 2 次 → 上线
)

// ==============================

type Monitor struct {
    Device
    client  modbus.Client
    failCnt int
    okCnt   int
    online  bool
}

func NewMonitor(d Device) *Monitor {
    return &Monitor{
        Device: d,
        client: modbus.NewClient(modbus.NewTCPClientProvider(
            fmt.Sprintf("%s:%d", d.IP, d.Port), // 目标设备 IP:端口
            modbus.WithEnableLogger(),          // 打开调试日志
            modbus.WithTCPTimeout(tcpTimeout),
        )),
        online: false,
    }
}

// 单次轮询
func (m *Monitor) pollOnce() bool {
    if err := m.client.Connect(); err != nil {
        return false
    }
    defer m.client.Close()

    coils, err := m.client.ReadCoils(1, 0, 10) // 起始位0，读10个
    if err == nil {
        fmt.Println("线圈值:", coils) // []bool
    }
    // 读 1 个保持寄存器，起始地址 0
    res, err := m.client.ReadHoldingRegisters(1, 0, 10) // slaveID=1, addr=0, qty=1
    fmt.Printf("Read registers: %v\n", res)
    // 1. 设置随机种子，否则每次运行结果都一样
    rand.Seed(time.Now().UnixNano())

    // 2. 生成 0~99 之间的随机整数

    m.stopMotor(1)
    m.client.WriteSingleRegister(1, 2, 1234)

    return err == nil
}

// 启动电机（线圈 #0 置 1）
func (m *Monitor) StartMotor(id byte) error {
    return m.client.WriteSingleCoil(id, 0, true)
}

// 关闭电机（线圈 #0 置 0）
func (m *Monitor) stopMotor(id byte) error {
    return m.client.WriteSingleCoil(id, 0, false)
}

// 状态机 + 报警
func (m *Monitor) update(success bool) {
    if success {
        m.failCnt = 0
        m.okCnt++
        if m.okCnt >= okThreshold && !m.online {
            m.online = true
            log.Printf("[RECOVER] 设备 %d (%s) 上线！", m.ID, m.IP)
        }
    } else {
        m.okCnt = 0
        m.failCnt++
        if m.failCnt >= failThreshold && m.online {
            m.online = false
            log.Printf("[ALARM] 设备 %d (%s) 离线！", m.ID, m.IP)
        }
    }
}

// 无限循环
func (m *Monitor) run(ctx context.Context) {
    t := time.NewTicker(pollInterval)
    defer t.Stop()

    for {
        select {
        case <-ctx.Done():
            return
        case <-t.C:
            m.update(m.pollOnce())
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    var wg sync.WaitGroup
    for _, d := range devices {
        m := NewMonitor(d)
        wg.Add(1)
        go func(m *Monitor) {
            defer wg.Done()
            m.run(ctx)
        }(m)
    }

    log.Println("基于 gomodbus/v2 的监控已启动，按 Ctrl+C 退出...")
    wg.Wait()
}
